﻿using System;
using System.Collections.Generic;
using System.Text;
using Studio.Network.Utilities;
using System.Drawing;
using Studio.Network.Kaixin001.Entities;
using Studio.Foundation.Text;
using Studio.Foundation.Json.Core.Conversion;
using System.Text.RegularExpressions;
using System.Threading;

namespace Studio.Network.Kaixin001
{

    public partial class ParkingAPI
    {

        public static readonly string URL_PARKING = "http://www.kaixin001.com/app/app.php?aid=1040";

        public static readonly string URL_PARKING_HOME = "http://www.kaixin001.com/!parking/index.php?verify={0}";

        public static readonly string URL_GOTO_NEIGHBOR ="http://www.kaixin001.com/!parking/!neighbor.php?verify={0}&puid={1}";
        public static readonly string URL_GOTO_USER = "http://www.kaixin001.com/!parking/!user.php?verify={0}&puid={1}";

        public static readonly string URL_PARKING_CALL ="http://www.kaixin001.com/!parking/call.php?verify={0}&park_uid={1}&parkid={2}&&acc={3}";
        public static readonly string URL_PARKING_POST ="http://www.kaixin001.com/!parking/post.php?verify={0}&parkid={1}&&acc={2}";
        public static readonly string URL_PARKING_PARK ="http://www.kaixin001.com/!parking/park.php?verify={0}&park_uid={1}&parkid={2}&carid={3}&neighbor={4}&acc={6}&first_fee_parking={5}";

        public static readonly string URL_PURCHASE ="http://www.kaixin001.com/!parking/purchase.php?verify={0}&carid={1}&color={2}";
        public static readonly string URL_UPDATECAR ="http://www.kaixin001.com/!parking/updatecar.php/?verify={0}&carid={1}&action=1&oldcarid={2}&color={3}";

        public static readonly string URL_MY_CARD = "http://www.kaixin001.com/!parking/mycard.php?verify={0}";

        public static readonly string URL_MY_CARD_HOME = "http://www.kaixin001.com/app/app.php?aid=1040&url=mycard.php";
        
        public static readonly string URL_BUY_CARD ="http://www.kaixin001.com/!parking/buycard.php?verify={0}&action=1&cardid={1}";
        public static readonly string URL_CARD_RESETPARK ="http://www.kaixin001.com/!parking/card_resetpark.php?verify={0}&cardid={1}";
        public static readonly string URL_CARD_RECYCLE = "http://www.kaixin001.com/!parking/card_recycle.php?verify={0}&cardid=2&carid={1}";
        
        public static readonly string URL_GIVE_FRIEND ="http://www.kaixin001.com/!parking/givefriend.php/?verify={0}&carid={1}&touid={2}&rcode={3}&code={4}";
        public static readonly string URL_GIVE_FRIEND_REFERER ="http://www.kaixin001.com/app/app.php?aid=1040&url=index.php";

        public static readonly string URL_USER_CAR = "http://www.kaixin001.com/!parking/usercar.php?verify={0}&puid={1}";

        public static readonly int CARD_ID_RECYCLE = 2;


        public static UserData GetUser(string verify)
        {
            string acc;
            FriendData[] friends;
            return ParkingAPI.GetUser(verify, out acc, out friends);
        }
        
        public static UserData GetUser(string verify, out string acc, out FriendData[] friends)
        {
            string response;
            return ParkingAPI.GetUser(verify, out acc, out friends, out response);        
        }

        public static UserData GetUser(string verify, out string acc, out FriendData[] friends, out string response)
        {
            HttpHelper http = KXInterface.HttpTransportation();
            string url = string.Format(URL_PARKING_HOME, verify);
            response = http.POST(url);
            UserData userData = ParkingAPI.ParseUserData(response);
            acc = ParkingAPI.ParseAccCode(response);
            friends = ParkingAPI.ParseFriendData(response);
            return userData;
        }

        public static UserData GotoUser(string verify)
        {
            HttpHelper http = KXInterface.HttpTransportation();
            int uid = ParkingAPI.ParseUid(verify);
            if (0 == uid) return null;
            string url = string.Format(URL_USER_CAR, verify, uid);
            string response = http.POST(url);
            UserData userData = ParkingAPI.ParseUserData(response);
            return userData;
        }

        public static UserData GotoUser(string verify, int uid)
        {
            HttpHelper http = KXInterface.HttpTransportation();
            string url = string.Format(URL_GOTO_USER, verify, uid);
            string data = http.POST(url, ParkingAPI.URL_PARKING);
            return JsonConvert.Import<UserData>(data);
        }

        /// <summary>
        /// load neighbor information
        /// </summary>
        public static UserData GotoNeighbor(string verify, int uid)
        {
            HttpHelper http = KXInterface.HttpTransportation();
            string url = string.Format(URL_GOTO_NEIGHBOR, verify, uid);
            string data = http.POST(url, ParkingAPI.URL_PARKING);
            return JsonConvert.Import<UserData>(data);
        }

        /// <summary>
        /// Parse uid from verify
        /// </summary>
        /// <param name="verify"></param>
        /// <returns></returns>
        public static int ParseUid(string verify)
        {
            int uid;
            if (string.IsNullOrEmpty(verify) || 0 >= verify.IndexOf('_')) return 0;
            string uid_string = verify.Substring(0, verify.IndexOf('_'));
            int.TryParse(uid_string, out uid);
            return uid;
        }


        public static IList<Card> ReadCards(string verify)
        {
            IList<Card> cards = new List<Card>();
            HttpHelper http = KXInterface.HttpTransportation();
            string url = string.Format(URL_MY_CARD, verify);
            string response = http.POST(url, ParkingAPI.URL_PARKING);
            string KEY = "hascontent";
            if(response.IndexOf(KEY) < 0) return cards;
            response = StringUtilities.Cut(response, KEY, KEY);
            string[] splitted = response.Split(new string[] { "javascript" }, StringSplitOptions.RemoveEmptyEntries);
            // from the 2nd, not ZERO.
            for (int i = 1; i < splitted.Length; i++)
            {
                int cardid, amount;
                int.TryParse(StringUtilities.Cut(splitted[i], "usecard('", "');"), out cardid);
                Card card = ParkingAPI.FindCard(cardid);
                if (null != card)
                {
                    card = card.Clone() as Card;
                    int.TryParse(StringUtilities.Cut(splitted[i - 1], "</span> ×", "</div>"), out amount);
                    if (amount > 0)
                    {
                        card.Amount = amount;
                        cards.Add(card);
                    }
                }
            }
            return cards;
        }

        static Card FindCard(int cardid)
        {
            foreach (Card card in ParkingAPI.CARDS)
                if (card.Id == cardid)
                    return card;
            return null;
        }

        public static string BuyCard(string verify, int cardid)
        {
            string url = string.Format(URL_BUY_CARD, verify, cardid);
            HttpHelper http = KXInterface.HttpTransportation();
            string response = http.POST(url);
            return response;
        }

        public static string UseCardRecycle(string verify, int carid)
        {
            string url = string.Format(URL_CARD_RECYCLE, verify, carid);
            HttpHelper http = KXInterface.HttpTransportation();
            string response = http.POST(url);
            return response;
        }


        /// <summary>
        /// Purchase car
        /// </summary>
        public static UserData Purchase(string verify, int carid, int color)
        {
            string url = string.Format(URL_PURCHASE, verify, carid, color);
            HttpHelper http = KXInterface.HttpTransportation();
            string response = http.POST(url);
            return ParkingAPI.ParseUserData(response);
        }

        /// <summary>
        /// Update car
        /// </summary>
        public static string UpdateCar(string verify, int carid, int old_carid, int color)
        {
            string url = string.Format(URL_UPDATECAR, verify, carid, old_carid, color);
            HttpHelper http = KXInterface.HttpTransportation();
            string response = http.POST(url);
            int index = response.IndexOf("style=\"display:block\"");
            if (0 >= index)
                return "UpdateCar::Parse Response Failed.";
            response = response.Substring(index);
            string KEY_PURCHASE_MESSAGE = "<div class=\"tac c9 mt10\">";
            index = response.IndexOf(KEY_PURCHASE_MESSAGE);
            if (0 >= index)
                response = StringUtilities.Cut(response, "<strong>", "</strong>");
            else
                response = StringUtilities.Cut(response, KEY_PURCHASE_MESSAGE, "</div>");
            response = response.Replace("<br />", "\r\n");
            return response;
        }

        public static UserData ParseUserData(string response)
        {
            UserData data = null;
            try
            {
                response = StringUtilities.Cut(response, "var v_userdata = ", "\n");
                response.Replace("\\/", "/");
                data = JsonConvert.Import<UserData>(response);
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine(ex);
            }
            return data;
        }

        public static FriendData[] ParseFriendData(string response)
        {
            FriendData[] data = null;
            try
            {
                response = StringUtilities.Cut(response, "var v_frienddata = ", "\n");
                response.Replace("\\/", "/");
                data = JsonConvert.Import<FriendData[]>(response);
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine(ex);
            }
            return data;
        }

        public static string ParseVerify(string response)
        {
            response = StringUtilities.Cut(response, "g_verify = \"", "\";");
            if (5 == response.Split(new char[] { '_' }).Length)
                return response;
            else
                return null;
        }

        /// <summary>
        /// Modified From Google Code, Parker
        /// </summary>
        public static string ParseAccCode(string response)
        {
            string Pattern = "";
            string accCode = "";
            string script = "";
            string script_tmp2 = "";
            string var_values = "";

            //得到所有script段
            Pattern = @"<script.*?>(?<x>.*?)</script>";
            MatchCollection scripts = Regex.Matches(response, Pattern, RegexOptions.Singleline);

            //查找符合要求的script段
            Pattern = @"function\s*?acc";
            foreach (Match script_tmp in scripts)
            {
                if (Regex.IsMatch(script_tmp.Groups["x"].ToString(), Pattern, RegexOptions.Singleline))
                {
                    script = script_tmp.Groups["x"].ToString();
                }
            }

            if (script.Length == 0) return null;

            //区分函数体内的和函数体外的声明
            //移除所有函数体
            script_tmp2 = script;
            Pattern = @"function.*?[^{]*?{[^{}]*(((?'Open'{)[^{}]*)+((?'-Open'})[^{}]*)+)*(?(Open)(?!))}";
            script_tmp2 = Regex.Replace(script, Pattern, "", RegexOptions.Singleline);
            //TraceLog.Print("script_tmp2=>{0}\n", script_tmp2);

            //记录所有全局的声明
            Pattern = @"var.*?=.*?"".*?"".*?;";
            foreach (Match var_value in Regex.Matches(script_tmp2, Pattern, RegexOptions.Multiline))
            {
                var_values = var_values + var_value.ToString();
            }

            //记录acc()
            Pattern = @"function\s*?acc[^{]*?{[^{}]*(((?'Open'{)[^{}]*)+((?'-Open'})[^{}]*)+)*(?(Open)(?!))}";
            Match acc_f = Regex.Match(script, Pattern, RegexOptions.Singleline);

            //全局声明在前,acc()在后
            script = var_values + acc_f.ToString();
            //TraceLog.Print("script=>{0}\n", script);

            accCode = ScriptHelper.RunJs(script + "acc();"); //动态得到acc结果

            return accCode;
        }


        /// <summary>
        /// Call Police
        /// </summary>
        public static ParkData ParkingCall(string verify, string acc, int park_uid, int parkid)
        {
            HttpHelper http = KXInterface.HttpTransportation();
            string url = string.Format(URL_PARKING_CALL, verify, park_uid, parkid, acc);
            string response = http.POST(url, URL_PARKING);
            return JsonConvert.Import<ParkData>(response);
        }

        /// <summary>
        /// Post the car by parkId
        /// </summary>
        public static ParkData ParkingPost(string verify, string acc, int parkid)
        {
            HttpHelper http = KXInterface.HttpTransportation();
            string url = string.Format(URL_PARKING_POST, verify, parkid, acc);
            string response = http.POST(url, URL_PARKING);
            return JsonConvert.Import<ParkData>(response);
        }

        /// <summary>
        /// Park a car to a park
        /// </summary>
        public static ParkData ParkingPark(string verify, string acc, int park_uid, int parkid, int carid, int neighbor, 
            int first_free_parking, int first_fee_parking)
        {
            HttpHelper http = KXInterface.HttpTransportation();
            int first = ParkData.IsParkFree(parkid) ? first_free_parking : first_fee_parking;
            string url = string.Format(URL_PARKING_PARK, verify, park_uid, parkid, carid, neighbor, first, acc);
            string park = http.POST(url, URL_PARKING);
            return JsonConvert.Import<ParkData>(park);
        }


        public static string ReadVerify(Account account)
        {
            HttpHelper http = KXInterface.HttpTransportation();
            // login
            string url = string.Format(KXInterface.URL_LOGIN, account.Email, account.Pass);
            http.POST(url);
            // parking home
            string response = http.GET(URL_PARKING, KXInterface.URL_KX_HOME);
            return ParkingAPI.ParseVerify(response);
        }


        /// <summary>
        /// Parking 
        /// </summary>
        public static void Parking(string verify, int minCash, int delay)
        {
            string acc;
            FriendData[] friends;
            UserData data = ParkingAPI.GetUser(verify, out acc, out friends);
            if (null == data || null == friends) return;
            // cars
            IList<Car> carList = new List<Car>();
            foreach (Car car in data.car)
                if (0 == car.park_uid)          //  Unparked
                    carList.Add(car);
                else if(car.park_profit >= minCash) // Profited
                    carList.Add(car);
                
            // friends
            IList<FriendData> friendList = new List<FriendData>();
            foreach (FriendData friend in friends)
                if (0 == friend.full)
                    friendList.Add(friend);

            // There are 2 loops:
            // Outer: Friends
            // Inner: (Parkings, Cars)

            // not-full friend index
            // int f = 0;
            while (0 < friendList.Count && 0 < carList.Count)
            {
                // try each parks in friends
                FriendData friend = friendList[0];

                UserData fData;
                if (0 == friend.neighbor)
                    fData = ParkingAPI.GotoUser(verify, friend.uid);
                else
                    fData = ParkingAPI.GotoNeighbor(verify, friend.uid);

                // for each parking
                IList<Parking> parkList = new List<Parking>();
                foreach (Parking park in fData.parking)
                    if (park.is_empty && false == park.is_free)
                        parkList.Add(park);

                // to-be-parked car index
                int c = 0;
                int p = 0;
                while (p < parkList.Count && c < carList.Count)
                {
                    Car car = carList[c];
                    Parking park = parkList[p];

                    // Park
                    if (friend.uid != car.park_uid)
                    {
                        Console.WriteLine("[{0}][Parking][{1}] Please Wait...", data.user.real_name, car.car_name);
                        Thread.Sleep(delay);
                        ParkData parkData = ParkingAPI.ParkingPark(verify, acc, friend.uid, park.parkid, car.carid,
                            friend.neighbor, data.user.first_free_parking, data.user.first_fee_parking);

                        if (0 == parkData.errno)
                        {
                            if (0 != car.park_uid)
                                // new free friend would be found
                                foreach (FriendData f in friends)
                                    if (f.uid == car.park_uid)
                                        friendList.Add(f);

                            carList.Remove(car);
                            parkList.Remove(park);
                        }
                        else
                        {
                            // try all (c, p) combinations
                            if (++c >= carList.Count)
                            {
                                c = 0;
                                p++;
                            }
                        }
                    }
                }
                friendList.Remove(friend);
            }
        }


        public static string GiveFriend(string verify, int carid, int touid, string rcode, string code)
        {
            HttpHelper http = KXInterface.HttpTransportation();
            string url = string.Format(ParkingAPI.URL_GIVE_FRIEND, verify, carid, touid, rcode, code);
            string response = http.POST(url, ParkingAPI.URL_GIVE_FRIEND_REFERER);

            string KEY_BLOCK_DIV = "style=\"display:block\"";
            int index = response.IndexOf(KEY_BLOCK_DIV);
            if (0 >= index)
                return "GiveFriend::Parse Response Failed.";
            response = response.Substring(index);
            response = StringUtilities.Cut(response, "<strong>", "</strong>");
            response = response.Replace("<br />", "\r\n");
            return response;
        }

    }
}
